package com.kingmed.kmss.auth.service.impl;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.kingmed.kmss.auth.config.WeaverConfig;
import com.kingmed.kmss.common.dto.auth.CustomMessageReq;
import com.kingmed.kmss.auth.service.WeaverService;
import com.kingmed.kmss.common.utils.kingmed.HttpTookit;
import com.kingmed.kmss.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 泛微OA对接
 * @author rain
 * @date 2023/5/15 11:41
 */
@Service
@Slf4j
public class WeaverServiceImpl implements WeaverService {

    public static final String RESULT_SUCCESS = "success";

    @Autowired
    private WeaverConfig weaverConfig;


    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private final static String KEY_REGIST = "weaverServiceImpl:regist";
    private final static String KEY_TOKEN = "weaverServiceImpl:token";
    private final static String KEY_LOCAL_PRIVATE_KEY = "weaverServiceImpl:regist:LOCAL_PRIVATE_KEY";
    private final static String KEY_LOCAL_PUBLIC_KEY = "weaverServiceImpl:regist:LOCAL_PUBLIC_KEY";


    @Override
    public String restLogin(String userName, String password) {
        String url =  weaverConfig.getWeaverServerUrl() + "/sso/v1/tickets";

        Map<String, Object> params = new HashMap<>(3);
        params.put("username", userName);
        params.put("password", password);
        params.put("service", "KMC");

        // 调用ECOLOGY系统发消息接口，消息推送接口返回为true，代表消息成功加入缓存，实际消息是否发送成功，请查看OA后台消息推送日志，和EM消息日志
        log.info("=====sendPost=====url:" + url);
        log.info("=====sendPost=====form:" + JSONUtil.parseObj(params));

        String result = HttpTookit.doPostGetHeader(url, params, "Location");
        if (StringUtils.isNotEmpty(result)) {
            String tgt = result.substring(result.lastIndexOf("/") + 1);
            log.info("=====sendPost=====tgt:" + tgt);
            return tgt;
        }
        return null;
    }

    @Override
    public String getTicket(String tgt) {
        String url = weaverConfig.getWeaverServerUrl() + "/sso/v1/tickets/" + tgt;
        Map<String, Object> params = new HashMap<>(1);
        params.put("service", "KMC");

        // 调用ECOLOGY系统发消息接口，消息推送接口返回为true，代表消息成功加入缓存，实际消息是否发送成功，请查看OA后台消息推送日志，和EM消息日志
        log.info("=====sendPost=====url:" + url);
        log.info("=====sendPost=====form:" + JSONUtil.parseObj(params));
        String result = HttpTookit.doPostGetBody(url, params);
        log.info("=====sendPost=====result:" + result);
        return result;
    }

    @Override
    public String restValidate(String ticket, String service) {
        /*String url = weaverConfig.getWeaverServerUrl() + "/sso/proxyValidate";

        Map<String, Object> params = new HashMap<>(2);
        params.put("ticket", ticket);
        //params.put("service", "KMC");
        if (StringUtils.isEmpty(service)) {
            params.put("service", "KMC");
        } else {
            params.put("service", service);
        }


        // 调用ECOLOGY系统发消息接口，消息推送接口返回为true，代表消息成功加入缓存，实际消息是否发送成功，请查看OA后台消息推送日志，和EM消息日志
        log.info("=====sendPost=====url:" + url);
        log.info("=====sendPost=====form:" + JSONUtil.parseObj(params));
        String result = HttpTookit.doPostGetBody(url, params);
        log.info("=====sendPost=====result:" + result);
        if (StringUtil.isNotEmpty(result)) {
            try {
                Document document = DocumentHelper.parseText(result);
                Element rootElement = document.getRootElement();
                Element authen = rootElement.element("authenticationSuccess");
                Element user = authen.element("user");
                String userCode = user.getStringValue();
                log.info("=====sendPost=====userCode:" + userCode);
                return userCode;
            } catch (Throwable e) {
                log.error("获取用户名失败", e);
            }
        }*/
        return null;
    }


    @Override
    public String sendMsg(String receiverCode, String title, CustomMessageReq customMessageReq) {
        customMessageReq.setTitle(title);
        customMessageReq.setWorkCodeList(receiverCode);

        if (customMessageReq.getLinkUrl() != null) {
            customMessageReq.setLinkUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkUrl());
        }
        if (customMessageReq.getLinkMobileUrl() != null) {
            customMessageReq.setLinkMobileUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkMobileUrl());
        }

        return sendCustomMessageSingle(customMessageReq);
    }

    @Override
    public String sendMsg(String receiverCode, String title, String context) {
        CustomMessageReq customMessageReq = JSONUtil.toBean(context, CustomMessageReq.class);
        customMessageReq.setTitle(title);
        customMessageReq.setWorkCodeList(receiverCode);

        if (customMessageReq.getLinkUrl() != null) {
            customMessageReq.setLinkUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkUrl());
        }
        if (customMessageReq.getLinkMobileUrl() != null) {
            customMessageReq.setLinkMobileUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkMobileUrl());
        }

        return sendCustomMessageSingle(customMessageReq);
    }

    @Override
    public String sendCustomMessageSingle(CustomMessageReq customMessageReq) {
        String url = weaverConfig.getWeaverServerUrl() + "/api/ec/dev/message/sendCustomMessageSingle";
        if (customMessageReq.getLinkUrl() != null) {
            customMessageReq.setLinkUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkUrl());
        }
        if (customMessageReq.getLinkMobileUrl() != null) {
            customMessageReq.setLinkMobileUrl(weaverConfig.getSourceServiceUrl() + customMessageReq.getLinkMobileUrl());
        }
        return sendPost(customMessageReq, url);
    }

    @Override
    public String alterCustomMessageSingle(CustomMessageReq customMessageReq) {
        String url = weaverConfig.getWeaverServerUrl() + "/api/ec/dev/message/alterCustomMessageSingle";
        return sendPost(customMessageReq, url);
    }

    @Override
    public String deleteCustomMessageSingle(CustomMessageReq customMessageReq) {
        String url = weaverConfig.getWeaverServerUrl() + "/api/ec/dev/message/deleteCustomMessageSingle";
        return sendPost(customMessageReq, url);
    }

    /**
     * 发送接口请求
     *
     * @param customMessageReq
     * @param url
     * @return
     */
    private String sendPost(CustomMessageReq customMessageReq, String url) {
        customMessageReq.setCode(weaverConfig.getCode());
        // ECOLOGY返回的token
        JSONObject tokenObj = getToken();

        if (tokenObj == null) {
            return "获取token失败";
        }

        if (tokenObj.getInt("code", -1) != 0) {
            return tokenObj.getStr("msg");
        }

        String weaverToken = tokenObj.getStr("token");

        if (StringUtils.isEmpty(weaverToken)) {
            redisTemplate.boundValueOps(KEY_REGIST).set(null);
            redisTemplate.boundValueOps(KEY_TOKEN).set(null);
            return "获取token失败";
        }

        // 封装参数到请求头
        Map<String, String> heads = new HashMap<>(3);
        heads.put("appid", weaverConfig.getWeaverAppId());
        heads.put("token", weaverToken);
        heads.put("skipsession", "1");

        // 调用ECOLOGY系统发消息接口，消息推送接口返回为true，代表消息成功加入缓存，实际消息是否发送成功，请查看OA后台消息推送日志，和EM消息日志
        log.info("=====sendPost=====url:" + url);
        log.info("=====sendPost=====form:" + JSONUtil.parseObj(customMessageReq));
        log.info("=====sendPost=====heads:" + JSONUtil.parseObj(heads));
        String data = HttpTookit.doPost(url, JSONUtil.parseObj(customMessageReq), heads);
        log.info("=====sendPost=====result：" + data);
        JSONObject result = JSONUtil.parseObj(data);
        if (result.getBool("status", false)) {
            return RESULT_SUCCESS;
        } else {
            redisTemplate.boundValueOps(KEY_REGIST).set(null);
            redisTemplate.boundValueOps(KEY_TOKEN).set(null);
            return result.getStr("msg");
        }
    }

    /**
     * 第一步：
     * <p>
     * 调用ecology注册接口,根据appid进行注册,将返回服务端公钥和Secret信息
     */
    public JSONObject regist() {

        BoundValueOperations<String, Object> weaverRegist = redisTemplate.boundValueOps(KEY_REGIST);
        Object obj = weaverRegist.get();
        if (!Objects.isNull(obj) && obj instanceof JSONObject) {
            return (JSONObject) obj;
        }

        BoundValueOperations<String, Object> weaverLocalPrivateKey = redisTemplate.boundValueOps(KEY_LOCAL_PRIVATE_KEY);
        BoundValueOperations<String, Object> weaverLocalPublicKey = redisTemplate.boundValueOps(KEY_LOCAL_PUBLIC_KEY);

        String publicKey = (String) weaverLocalPublicKey.get();
        String privateKey = (String) weaverLocalPrivateKey.get();

        if (Objects.isNull(publicKey) || Objects.isNull(privateKey)) {
            // 获取当前系统RSA加密的公钥
            cn.hutool.crypto.asymmetric.RSA rsa = new cn.hutool.crypto.asymmetric.RSA();
            publicKey = rsa.getPublicKeyBase64();
            privateKey = rsa.getPrivateKeyBase64();

            // 客户端RSA私钥
            weaverLocalPrivateKey.set(privateKey);
            // 客户端RSA公钥
            weaverLocalPublicKey.set(publicKey);
        }

        Map<String, String> heads = new HashMap<>(2);
        // 封装参数到请求头
        heads.put("appid", weaverConfig.getWeaverAppId());
        heads.put("cpk", publicKey);
        // 调用ECOLOGY系统接口进行注册
        log.info("=====regist=====,heads:" + JSONUtil.toJsonStr(heads));
        String data = HttpTookit.doPost(weaverConfig.getWeaverServerUrl() + "/api/ec/dev/auth/regist", heads);
        // 打印ECOLOGY响应信息
        log.info("=====regist=====,data" + data);
        JSONObject datas = JSONUtil.parseObj(data);
        if (datas.getInt("code", -1) != 0) {
            weaverRegist.set(null);
        } else {
            // token有效期30分钟，设置25分钟失效，保证有效
            weaverRegist.set(datas, 25, TimeUnit.MINUTES);
        }
        return datas;
    }

    /**
     * 第二步：
     * <p>
     * 通过第一步中注册系统返回信息进行获取token信息
     */
    public JSONObject getToken() {
        BoundValueOperations<String, Object> weaverServerToken = redisTemplate.boundValueOps(KEY_TOKEN);
        JSONObject token = (JSONObject) weaverServerToken.get();
        if (token != null) {
            return token;
        }

        // 从系统缓存或者数据库中获取ECOLOGY系统公钥和Secret信息

        JSONObject registData = regist();
        if (registData.getInt("code", -1) != 0) {
            return registData;
        }

        String secret = registData.getStr("secrit");
        String spk = registData.getStr("spk");

        // 公钥加密,所以RSA对象私钥为null
        cn.hutool.crypto.asymmetric.RSA rsa = new cn.hutool.crypto.asymmetric.RSA(null, spk);
        // 对秘钥进行加密传输，防止篡改数据
        String encryptSecret = rsa.encryptBase64(secret, CharsetUtil.CHARSET_UTF_8, KeyType.PublicKey);
        // 调用ECOLOGY系统接口进行注册
        Map<String, String> heads = new HashMap<>(3);
        // 封装参数到请求头
        heads.put("appid", weaverConfig.getWeaverAppId());
        heads.put("secret", encryptSecret);
        // token，设置30分钟有效
        heads.put("time", "1800");
        log.info("=====getoken=====,heads:" + JSONUtil.toJsonStr(heads));
        String data = HttpTookit.doPost(weaverConfig.getWeaverServerUrl() + "/api/ec/dev/auth/applytoken", heads);
        log.info("=====getoken=====,data:" + data);
        // ECOLOGY返回的token

        JSONObject result = JSONUtil.parseObj(data);
        if (result.getInt("code", -1) != 0) {
            weaverServerToken.set(null);
        } else {
            // token有效期30分钟，设置25分钟失效，保证有效
            weaverServerToken.set(result, 25, TimeUnit.MINUTES);
        }
        return result;
    }

    @Override
    public String restValidate(String ticket) {
        /*String url = weaverConfig.getWeaverServerUrl() + "/sso/proxyValidate";

        Map<String, Object> params = new HashMap<>(2);
        params.put("ticket", ticket);
        params.put("service", "KMC");

        // 调用ECOLOGY系统发消息接口，消息推送接口返回为true，代表消息成功加入缓存，实际消息是否发送成功，请查看OA后台消息推送日志，和EM消息日志
        log.info("=====sendPost=====url:" + url);
        log.info("=====sendPost=====form:" + JSONUtil.parseObj(params));
        String result = HttpTookit.doPostGetBody(url, params);
        log.info("=====sendPost=====result:" + result);
        if (StringUtils.isNotEmpty(result)) {
            try {
                Document document = DocumentHelper.parseText(result);
                Element rootElement = document.getRootElement();
                Element authen = rootElement.element("authenticationSuccess");
                Element user = authen.element("user");
                String userCode = user.getStringValue();
                log.info("=====sendPost=====userCode:" + userCode);
                return userCode;
            } catch (Throwable e) {
                log.error("获取用户名失败", e);
            }
        }*/
        return null;
    }
}
